Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds within and eval_code to teal_data_module #983

Merged
merged 29 commits into from
Dec 5, 2023
Merged

Adds within and eval_code to teal_data_module #983

merged 29 commits into from
Dec 5, 2023

Conversation

averissimo
Copy link
Contributor

@averissimo averissimo commented Nov 28, 2023

Pull Request

Fixes #nnn

Changes description

  • Adds within and eval_code to teal_data_module
  • Adds tests for new functions (100% coverage)
  • Updates data-as-shiny-module vignette
  • 🟠 Moves {teal.code} from Suggests to Imports

@averissimo averissimo added enhancement New feature or request core labels Nov 28, 2023
Comment on lines +72 to +87
within.teal_data_module <- function(data, expr, ...) {
expr <- substitute(expr)
extras <- list(...)

# Add braces for consistency.
if (!identical(as.list(expr)[[1L]], as.symbol("{"))) {
expr <- call("{", expr)
}

calls <- as.list(expr)[-1]

# Inject extra values into expressions.
calls <- lapply(calls, function(x) do.call(substitute, list(x, env = extras)))

eval_code(object = data, code = as.expression(calls))
}
Copy link
Contributor Author

@averissimo averissimo Nov 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The body is a copy from teal.code:::within.qenv, it just prepares the arguments to call eval_code() (data is unchanged)

So in practice it could be replaced with code below (reducing duplicated code accross {teal.*}):

Thoughts?

Suggested change
within.teal_data_module <- function(data, expr, ...) {
expr <- substitute(expr)
extras <- list(...)
# Add braces for consistency.
if (!identical(as.list(expr)[[1L]], as.symbol("{"))) {
expr <- call("{", expr)
}
calls <- as.list(expr)[-1]
# Inject extra values into expressions.
calls <- lapply(calls, function(x) do.call(substitute, list(x, env = extras)))
eval_code(object = data, code = as.expression(calls))
}
within.teal_data_module <- function(data, expr, ...) {
within.qenv <- getFromNamespace("within.qenv", "teal.code")
within.qenv(data, expr, ...)
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I think getS3method("within", "qenv", envir = as.environment(getNamespace("teal.code"))) would be a better choice.
  2. It shouldn't be necessary anyway because teal.code must be installed when teal is.
  3. At the moment within only processes the expression and calls eval_code. In this context this is a valid simplification. I'm not sure, though 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I think getS3method("within", "qenv", envir = as.environment(getNamespace("teal.code"))) would be a better choice.
  2. It shouldn't be necessary anyway because teal.code must be installed when teal is.

That's better! Is the envir parameter required? (as you said, teal.code is imported and it seems to find the within)

  1. At the moment within only processes the expression and calls eval_code. In this context this is a valid simplification. I'm not sure, though 🤔

@vedhav brough a smilar concern, I'm on the fence as I prefer to minimize repetitive code, but I don't think this solution is "best practice" (calling within.qenv with a different data object seems like a red flag).

I would prefer if there was within.default (non-exported) or .generic_within in {teal.code} that was the backbone of both of those calls and still allow for deviations in the future of within.qenv that wouldn't affect within.teal_data_module.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's better! Is the envir parameter required?

It isn't but just in case there is a different within.qenv defined somewhere...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer if there was within.default

The within generic is a base function so defining a default that suits our particular classes would cause a mess.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The within generic is a base function so defining a default that suits our particular classes would cause a mess.

Yup, so a .generic_within function would be best if we wanted to go this route.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the .default was a suggestion if it didn't interfere with base::within (by not exporting it, but even then it might be "dangerous")

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, but S3 methods must be exported 😉

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gogonzo would you like to pitch in?

Copy link
Contributor

@pawelru pawelru Dec 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One interesting pattern that I have found when working on the verdepcheck is to make a simple (i.e. non S3 / non S4 etc.) (implementation) function for each method and these methods are essentially a one-liner calling those functions. Please find an example in R6 context: https://github.com/r-lib/pkgdepends/blob/main/R/pkg-plan.R - all public methods are calling private (implementation) functions.

Then you can re-use those implementation functions from multiple classes but there are some obvious drawbacks though such as number of objects in a package, documentation, maintenance, debugging etc.

This however is not addressing an exporting / importing issue mentioned here 😈

@averissimo averissimo marked this pull request as ready for review November 28, 2023 13:13
Copy link
Contributor

github-actions bot commented Nov 28, 2023

badge

Code Coverage Summary

Filename                          Stmts    Miss  Cover    Missing
------------------------------  -------  ------  -------  -------------------------------------------------------------------------------------------------------------------------------
R/dummy_functions.R                  92      50  45.65%   9-71
R/get_rcode_utils.R                  38       1  97.37%   50
R/include_css_js.R                   24       0  100.00%
R/init.R                             79      25  68.35%   139, 164-185, 217-219, 221-223, 225-226
R/landing_popup_module.R             25      25  0.00%    61-87
R/module_filter_manager.R           107      29  72.90%   62-70, 79-84, 228, 233-246
R/module_nested_tabs.R              174      14  91.95%   72, 119, 138-145, 163, 216, 238, 271
R/module_snapshot_manager.R         209     157  24.88%   87-99, 127-136, 140-152, 154-161, 168-182, 186-188, 190-195, 198-208, 211-227, 236-251, 265-288, 291-302, 305-311, 325, 346-369
R/module_tabs_with_filters.R         73       2  97.26%   95, 140
R/module_teal_with_splash.R         120      11  90.83%   73, 87-95, 122
R/module_teal.R                     141       8  94.33%   68, 71, 158-159, 165, 196, 204-205
R/modules_debugging.R                18      18  0.00%    25-44
R/modules.R                         143      26  81.82%   119, 132, 226-229, 243-248, 259-263, 378-421
R/reporter_previewer_module.R        18       2  88.89%   26, 30
R/show_rcode_modal.R                 20      20  0.00%    16-37
R/tdata.R                            39       1  97.44%   158
R/teal_data_module-eval_code.R       34       0  100.00%
R/teal_data_module.R                  6       0  100.00%
R/teal_reporter.R                    60       5  91.67%   65, 116-117, 120, 137
R/teal_slices-store.R                25       0  100.00%
R/teal_slices.R                      59      12  79.66%   135-148
R/utils.R                           108      27  75.00%   113-140
R/validate_inputs.R                  32       0  100.00%
R/validations.R                      58      37  36.21%   109-371
R/zzz.R                              11       7  36.36%   3-14
TOTAL                              1713     477  72.15%

Diff against main

Filename                          Stmts    Miss  Cover
------------------------------  -------  ------  --------
R/teal_data_module-eval_code.R      +34       0  +100.00%
TOTAL                               +34       0  +0.56%

Results for commit: b1625ba

Minimum allowed coverage is 80%

♻️ This comment has been updated with latest results

Copy link
Contributor

github-actions bot commented Nov 28, 2023

Unit Tests Summary

    1 files    19 suites   12s ⏱️
207 tests 207 ✔️ 0 💤 0
403 runs  403 ✔️ 0 💤 0

Results for commit b1625ba.

♻️ This comment has been updated with latest results.

Copy link
Contributor

github-actions bot commented Nov 28, 2023

Unit Test Performance Difference

Test Suite $Status$ Time on main $±Time$ $±Tests$ $±Skipped$ $±Failures$ $±Errors$
teal_data_module-eval_code 👶 $+0.11$ $+16$ $0$ $0$ $0$
Additional test case details
Test Suite $Status$ Time on main $±Time$ Test Case
module_teal_with_splash 👶 $+0.03$ srv_teal_with_splash_accepts_data_after_within.teal_data_module
module_teal_with_splash 👶 $+0.04$ srv_teal_with_splash_throws_error_when_within.teal_data_module_returns_NULL
module_teal_with_splash 👶 $+0.04$ srv_teal_with_splash_throws_error_when_within.teal_data_module_returns_arbitrary_object_other_than_teal_data_or_qenv.error_
module_teal_with_splash 👶 $+0.04$ srv_teal_with_splash_throws_error_when_within.teal_data_module_returns_qenv.error
teal_data_module-eval_code 👶 $+0.02$ eval_code.teal_data_module_handles_a_NULL_result
teal_data_module-eval_code 👶 $+0.01$ eval_code.teal_data_module_handles_an_arbitrary_object_other_than_teal_data_or_qenv.error_
teal_data_module-eval_code 👶 $+0.01$ eval_code.teal_data_module_propagates_qenv_error_from_the_original_first_call
teal_data_module-eval_code 👶 $+0.01$ eval_code.teal_data_module_throws_error_when_original_teal_data_module_result_is_not_reactive
teal_data_module-eval_code 👶 $+0.01$ eval_code.teal_data_module_ui_has_modified_namespace_for_id
teal_data_module-eval_code 👶 $+0.02$ eval_code.teal_data_module_will_execute_several_times_until_error
teal_data_module-eval_code 👶 $+0.02$ within.teal_data_module_modifies_the_reactive_tea_data_object
teal_data_module-eval_code 👶 $+0.01$ within.teal_data_module_returns_an_object_with_teal_data_module_class

Results for commit 9163527

♻️ This comment has been updated with latest results.

R/zzz.R Outdated Show resolved Hide resolved
Copy link
Contributor

@gogonzo gogonzo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are missing tests and poc for teal application. There are already tests on data (teal_data_module) output. I wonder what would be the output of eval_code(teal_data_module, code) if there is an error in teal_data_module or in the code.

tests/testthat/test-teal_data_module-eval_code.R Outdated Show resolved Hide resolved
tests/testthat/test-teal_data_module-eval_code.R Outdated Show resolved Hide resolved
R/teal_data_module-eval_code.R Outdated Show resolved Hide resolved
R/zzz.R Show resolved Hide resolved
@gogonzo gogonzo self-assigned this Dec 4, 2023
@chlebowa chlebowa self-assigned this Dec 4, 2023
Copy link
Contributor

@gogonzo gogonzo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing to add in my opinion. Good job!

R/teal_data_module-eval_code.R Outdated Show resolved Hide resolved
R/teal_data_module-eval_code.R Outdated Show resolved Hide resolved
R/teal_data_module-eval_code.R Outdated Show resolved Hide resolved
R/teal_data_module-eval_code.R Outdated Show resolved Hide resolved
Comment on lines +72 to +87
within.teal_data_module <- function(data, expr, ...) {
expr <- substitute(expr)
extras <- list(...)

# Add braces for consistency.
if (!identical(as.list(expr)[[1L]], as.symbol("{"))) {
expr <- call("{", expr)
}

calls <- as.list(expr)[-1]

# Inject extra values into expressions.
calls <- lapply(calls, function(x) do.call(substitute, list(x, env = extras)))

eval_code(object = data, code = as.expression(calls))
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gogonzo would you like to pitch in?

sep = "\n",
"Error when executing `teal_data_module`:",
paste0(
"It must always return a reactive with `teal_data`, it returns object of class(es): ",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As in srv_teal_with_splash, I believe this error message is for the app dev, not for the app user. It should shop up in the console, not in the app.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It depends. Let's say we have teal_data_module that reads csv files only and an app user select e.g. pdf file then we probably need to expose error message for app user.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then it is up to the module developer to validate the file choice.

R/teal_data_module-eval_code.R Outdated Show resolved Hide resolved
R/teal_data_module-eval_code.R Show resolved Hide resolved
Copy link
Contributor

@gogonzo gogonzo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please address comments and fix R CMD check

tests/testthat/test-teal_data_module-eval_code.R Outdated Show resolved Hide resolved
R/teal_data_module-eval_code.R Outdated Show resolved Hide resolved
@averissimo averissimo merged commit 32bfe75 into main Dec 5, 2023
24 checks passed
@averissimo averissimo deleted the ddl@main branch December 5, 2023 08:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants